package pcgen.android.app;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.SecurityException;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;

import android.app.Activity;
import android.app.Application;
import android.content.ComponentName;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

import pcgen.android.DefaultSharedPreferences;
import pcgen.android.Logger;
import pcgen.android.app.OptionMenusProvider;

public abstract class ActivityEx extends Activity implements OnSharedPreferenceChangeListener
{
	public int contextHelpId()
	{
		return -1;
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) 
    {
		try
		{
			super.onCreateOptionsMenu(menu);
			
			_optionsMenu = menu;
			
			// Begin - Pulled from droidfu
			_wasCreated = true;
			//_currentIntent = getIntent();

	        Application application = getApplication();
	        if (application instanceof ApplicationEx)
	        	((ApplicationEx)application).setActiveContext(getClass().getCanonicalName(), this);
	        // End - Pulled from droidfu
	        
			initializeOptionMenus(menu);
			
			OptionMenusProvider provider = getApplicationApp().getOptionMenusProvider();
			if (provider != null)
				provider.onCreateOptionsMenu(this, menu);
			
			// Generate any additional actions that can be performed on the
	        // overall list.  In a normal install, there are no additional
	        // actions found here, but this allows other applications to extend
	        // our menu with their own actions.
	        Intent intent = new Intent(null, getIntent().getData());
	        intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
	        menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0,
	        		new ComponentName(this, this.getClass()), null, intent, 0, null);
	        
	        initializeOptionMenusCompleted(menu);
	        
	    	return true;
		}
		catch (Throwable tr)
		{
			Logger.e(TAG, "onCreateOptionsMenu", tr);
		}
		
		return false;
    }
	
	@Override
    public boolean onOptionsItemSelected(MenuItem item) 
    {
    	try
    	{
    		super.onOptionsItemSelected(item);
    		
    		boolean handled = false;
	    	OptionMenusProvider provider = getApplicationApp().getOptionMenusProvider();
			if (provider != null)
				handled = provider.onOptionsItemSelected(this, item);
			
			if (!handled)
				handled = handleOptionsItemSelected(item);
			
			if (item.getItemId() == android.R.id.home)
			{
	            // app icon in Action Bar clicked; go home
	            Intent intent = new Intent(this, Activity.class);
	            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
	            startActivity(intent);
	            handled = true;
			}
			
			return handled;
    	}
		catch (Throwable tr)
		{
			Logger.e(TAG, "onOptionsItemSelected", tr);
		}
		
    	return false;
    }
	
	public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
	{	
	}

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) 
    {
    	try
    	{
	        super.onActivityResult(requestCode, resultCode, data);
	        
	        initializeActivityResult(requestCode, resultCode, data);
    	}
    	catch(Throwable tr)
    	{
    		Logger.e(TAG, "onActivityResult", tr);
    	}
    }
	
    @Override
	protected void onCreate(Bundle inState)
    {
		try
		{
			initializePre();
			
			super.onCreate(inState);
			
			if (inState != null)
				stateRestore(inState);
			
			int orientation = initializeOrientation();
			if (orientation > -1)
				setRequestedOrientation(orientation);

			getApplicationApp().setOptionMenusProvider(initializeOptionMenusProvider());
			
			getApplicationApp().setApplicationIsForeground(this);
			
			initializeContentView();
			
			initialize(inState);
			
			initializeMenu();
		}
		catch (Throwable tr)
		{
			Logger.e(TAG, "onCreate", tr);
		}
    }
	
    @Override
    protected void onDestroy()
    {
    	try
    	{
    		initializeDestroy();
	    	
    		getApplicationApp().removeApplicationIsForeground();
    		
    		super.onDestroy();
    	}
		catch (Throwable tr)
		{
			Logger.e(TAG, "onDestroy", tr);
		}
    }

    @Override
    protected void onNewIntent(Intent intent) 
    {
		try
		{
			super.onNewIntent(intent);
	    	
	    	// Begin - Pulled from droidfu
			_currentIntent = intent;
			// End - Pulled from droidfu
		}
		catch (Throwable tr)
		{
			Logger.e(TAG, "onNewIntent", tr);
		}
    }
	
	@Override
    protected void onPause()
	{
		try
		{
			stateSaveUser();
			
			initializePause();
				
			DefaultSharedPreferences.commit(this.getBaseContext());
	    	
			getApplicationApp().removeApplicationIsForeground();

	    	super.onPause();
	    	
	    	// Begin - Pulled from droidfu
			_wasInterrupted = false;
			// End - Pulled from droidfu
		}
		catch (Throwable tr)
		{
			Logger.e(TAG, "onPause", tr);
		}
    }
	
	@Override 
	public void onRestoreInstanceState(Bundle savedInstanceState) 
	{ 
		try
		{
			super.onRestoreInstanceState(savedInstanceState); 

			// Begin - Pulled from droidfu
			_wasInterrupted = true;
			// End - Pulled from droidfu
		}
		catch (Throwable tr)
		{
			Logger.e(TAG, "onRestoreInstanceState", tr);
		}
	}
	
	@Override
    protected void onResume()
	{
		try
		{
			super.onResume();
			
			getApplicationApp().setApplicationIsForeground(this);
			
			initializeResume();
	    	
			stateRestoreUser();
		}
		catch (Throwable tr)
		{
			Logger.e(TAG, "onResume", tr);
		}
    }
	
	@Override
    protected void onSaveInstanceState(Bundle outState)
	{
		try
		{
			if (outState != null)
				stateSave(outState);
			
			super.onSaveInstanceState(outState);
		}
		catch (Throwable tr)
		{
			Logger.e(TAG, "onSaveInstanceState", tr);
		}
	}

	protected boolean existsExternalFileApplication(String name)
		throws Throwable
	{
		return existsExternalFileApplication(name, "");
	}

	protected boolean existsExternalFileApplication(String name, String path)
		throws Throwable
    {
    	return existsExternalFile(getExternalStorageDirectoryApplication(), name, path);
    }

	protected boolean existsExternalFile(File root, String name, String path)
		throws Throwable
    {
		Validate.notNull(root);
		Validate.notEmpty(name);
		
    	try
    	{
    		if (!StringUtils.isEmpty(path))
				root = new File(root, path);
    		
    		File file = new File(root, name);
			return file.exists();
    	}
    	catch (Throwable tr)
    	{
    		Logger.e(TAG, "existsExternalFile", tr);
    		throw tr;
    	}
    }
	
	protected String[] getExternalFileList(File root, String path)
		throws Throwable
    {
    	Validate.notNull(root);
    	
		try
    	{
    		File temp = new File(root, path);
			if (!temp.exists())
				temp.mkdirs();
			
			return temp.list();
    	}
    	catch (Throwable tr)
    	{
    		Logger.e(TAG, "getExternalFileList", tr);
    		throw tr;
    	}
    }
	
	protected ApplicationEx getApplicationApp()
	{
		return (ApplicationEx)getApplication();
	}
	
	protected String[] getExternalFileList(String path)
		throws Throwable
    {
    	return getExternalFileList(getExternalStorageDirectory(), path);
    }
	
	protected String[] getExternalFileListApplication(String path)
		throws Throwable
    {
    	return getExternalFileList(getExternalStorageDirectoryApplication(), path);
    }
	
	protected SharedPreferences getPreferences()
	{
		return DefaultSharedPreferences.retrieve(this);
	}
	
	protected int getWindowFeatures() 
	{
        return AppUtils.getWindowFeatures(this);
    }
	
	protected boolean handleOptionsItemSelected(MenuItem item)
	{
		return false;
	}
	
	protected void initializePre()
    {
    }
	
	protected void initialize(Bundle savedInstanceState)
	{
	}
	
	protected void initializeActivityResult(int requestCode, int resultCode, Intent data) 
	{
	}
    
	protected void initializeContentView()
	{
	}
	
	protected void initializeDestroy()
	{
	}
    
	protected void initializeMenu()
	{
	}

	protected void initializeOptionMenus(Menu menu)
	{
	}
    
	protected void initializeOptionMenusCompleted(Menu menu)
	{
	}
	
	protected OptionMenusProvider initializeOptionMenusProvider()
	{
		return null;
	}
	
	protected int initializeOrientation()
	{
		return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
	}
	
	protected void initializePause()
	{
	}
	
	protected void initializeResume()
	{
	}

	protected boolean isRestoring() 
    {
        return _wasInterrupted;
    }

	protected boolean isResuming() 
    {
        return !_wasCreated;
    }

	protected boolean isLaunching() 
    {
        return !_wasInterrupted && _wasCreated;
    }

	protected boolean isApplicationBroughtToBackground() 
    {
        return AppUtils.isApplicationBroughtToBackground(this);
    }

	protected boolean isLandscapeMode() 
	{
        return getWindowManager().getDefaultDisplay().getOrientation() == 1;
    }

	protected boolean isPortraitMode() 
    {
        return !isLandscapeMode();
    }

	protected InputStream openExternalFileInput(String name)
		throws Throwable
	{
		return openExternalFileInput(name, "");
	}

	protected InputStream openExternalFileInput(File root, String name, String path)
		throws Throwable
    {
		Validate.notNull(root);
		Validate.notEmpty(name);
		
    	try
    	{
    		if (!StringUtils.isEmpty(path))
			{
				File temp = new File(root, path);
				if (!temp.exists())
					temp.mkdirs();
				root = temp;
			}
			
			File file = new File(root, name);
    		return new FileInputStream(file);
    	}
    	catch (Throwable tr)
    	{
    		Logger.e(TAG, "openExternalFileInput", tr);
    		throw tr;
    	}
    }

	protected InputStream openExternalFileInputApplication(String name)
		throws Throwable
	{
		return openExternalFileInputApplication(name, "");
	}

	protected InputStream openExternalFileInput(String name, String path)
		throws Throwable
    {
    	return openExternalFileInput(getExternalStorageDirectory(), name, path);
    }

	protected InputStream openExternalFileInputApplication(String name, String path)
		throws Throwable
    {
    	return openExternalFileInput(getExternalStorageDirectoryApplication(), name, path);
    }

	protected OutputStream openExternalFileOutput(String name)
		throws Throwable
	{
		return openExternalFileOutput(name, "");
	}

	protected OutputStream openExternalFileOutputApplication(String name)
		throws Throwable
	{
		return openExternalFileOutputApplication(name, "");
	}

	protected OutputStream openExternalFileOutput(File root, String name, String path)
    	throws Throwable
    {
    	Validate.notEmpty(name);
    	
    	try
    	{
    		if (root == null)
    			return null;
    		
    		if (!StringUtils.isEmpty(path))
			{
				File temp = new File(root, path);
				if (!temp.exists())
					temp.mkdirs();
				root = temp;
			}
			
			File file = new File(root, name);
			return new FileOutputStream(file);
    	}
    	catch (Throwable tr)
    	{
    		Logger.e(TAG, "openExternalFileOutput", tr);
    		throw tr;
    	}
    }

	protected OutputStream openExternalFileOutput(String name, String path)
    	throws Throwable
    {
		return openExternalFileOutput(getExternalStorageDirectory(), name, path);
    }

	protected OutputStream openExternalFileOutputApplication(String name, String path)
    	throws Throwable
    {
		return openExternalFileOutput(getExternalStorageDirectoryApplication(), name, path);
    }
	
	protected void stateRestore(Bundle inState)
	{
	}
	
	protected void stateRestoreUser()
	{
	}
	
	protected void stateSave(Bundle outState)
	{
	}
	
	protected void stateSaveUser()
	{
	}
    
    protected String stripExternalStorageDirectory(String path)
    	throws Throwable
    {
    	return stripExternalStorageDirectory(getExternalStorageDirectory(), path);
    }
    
    protected String stripExternalStorageDirectory(File root, String path)
    	throws Throwable
    {
    	Validate.notNull(root);
    	
    	try
    	{
    		if (!StringUtils.isEmpty(path))
    		{
    			String externalPath = root.getPath();
    			path = path.replace(externalPath, "");
    		}
    	}
    	catch (SecurityException sex)
    	{
    		throw sex;
    	}
    	catch (Throwable tr)
    	{
    		Logger.e(TAG, "stripExternalStorageDirectory", tr);
    		throw tr;
    	}
    	
    	return path;
    }
    
    protected String stripExternalStorageDirectoryApplication(String path)
    	throws Throwable
    {
    	return stripExternalStorageDirectory(getExternalStorageDirectoryApplication(), path);
    }
    
    public Menu getOptionMenu()
    {
    	return _optionsMenu;
    }
	
	private File getExternalStorageDirectory(File root)
		throws Throwable
	{
		Validate.notNull(root);
    	
    	try
    	{
	    	File external = ((ApplicationEx)getApplication()).getExternalStorageDirectoryApplication();
			if (!external.exists())
				throw new FileNotFoundException("Root external storage not found.");
			if (!external.canRead())
				throw new SecurityException("Cannot read from root external storage.");
			
			return external;
		}
    	catch (Throwable tr)
    	{
    		Logger.e(TAG, "stripExternalStorageDirectory", tr);
    		throw tr;
    	}
	}
	
	private File getExternalStorageDirectory()
		throws Throwable
	{
		return getExternalStorageDirectory(((ApplicationEx)getApplication()).getExternalStorageDirectory());
	}
	
	private File getExternalStorageDirectoryApplication()
		throws Throwable
	{
		return getExternalStorageDirectory(((ApplicationEx)getApplication()).getExternalStorageDirectoryApplication());
	}

	private Menu _optionsMenu;
	protected Intent _currentIntent;
	
	private boolean _wasCreated;
	private boolean _wasInterrupted;

	private static final String TAG = ActivityEx.class.getSimpleName();
}
